package svgedit.svg;

import java.awt.Shape;
import java.awt.geom.Rectangle2D;
import svgedit.gui.Marker.MarkerType;

/**
 * Element describing a rectangle.
 * 
 * Implements {@literal 9.8.1 Interface SVGRectElement}.
 */
public class SVGRectElement extends SVGStylableElement implements SVGDrawable
{

	private SVGLength x;
	private SVGLength y;
	private SVGLength width;
	private SVGLength height;

	public SVGRectElement(SVGDocument document)
	{
		super(document);
		x = new SVGLength(document, SVGLength.SVG_DIMENSION_X);
		y = new SVGLength(document, SVGLength.SVG_DIMENSION_Y);
		width = new SVGLength(document, SVGLength.SVG_DIMENSION_X);
		height = new SVGLength(document, SVGLength.SVG_DIMENSION_Y);
	}

	/**
	 * Gets the x coordinate of the rectangle. If the width is positive, this is
	 * the left edge; otherwise it is one pixel past the right edge.
	 * 
	 * @return the x coordinate of the rectangle
	 */
	public SVGLength getX()
	{
		return x;
	}

	/**
	 * Gets the y coordinate of the rectangle. If the height is positive, this
	 * is the top edge; otherwise it is one pixel past the bottom edge.
	 * 
	 * @return the y coordinate of the rectangle
	 */
	public SVGLength getY()
	{
		return y;
	}

	/**
	 * Gets the width of the rectangle. This may be negative.
	 * 
	 * @return the width
	 */
	public SVGLength getWidth()
	{
		return width;
	}

	/**
	 * Gets the height of the rectangle. This may be negative.
	 * 
	 * @return the height
	 */
	public SVGLength getHeight()
	{
		return height;
	}

	public void acceptVisitor(SVGVisitor visitor)
	{
		visitor.visitRect(this);
	}

	public double getAbsLeft()
	{
		double x1 = x.getValue();
		return Math.min(x1, x1 + width.getValue());
	}

	public double getAbsRight()
	{
		double x1 = x.getValue();
		return Math.max(x1, x1 + width.getValue());
	}

	public double getAbsTop()
	{
		double y1 = y.getValue();
		return Math.min(y1, y1 + height.getValue());
	}

	public double getAbsBottom()
	{
		double y1 = y.getValue();
		return Math.max(y1, y1 + height.getValue());
	}

	public double getAbsWidth()
	{
		return Math.abs(width.getValue());
	}

	public double getAbsHeight()
	{
		return Math.abs(height.getValue());
	}

	public Shape createShape()
	{
		return new Rectangle2D.Double(getAbsLeft(), getAbsTop(), getAbsWidth(),
				getAbsHeight());
	}

	@Override
	public void write(int indent)
	{
		System.out.printf("%" + indent + "s", " ");
		System.out.printf("<rect id='%s'>\n", this.toString());

	}

	@Override
	public Shape getSelectionStroke()
	{
		Shape strokedShape = super.getSelectionStroke();

		this.addMarker(strokedShape, this.getBounds().getX(), this.getBounds()
				.getY(), MarkerType.RECT_TOP_LEFT);
		this.addMarker(strokedShape, this.getBounds().getCenterX(), this
				.getBounds().getY(), MarkerType.RECT_TOP_CENTER);
		this.addMarker(strokedShape, this.getBounds().getMaxX(), this
				.getBounds().getY(), MarkerType.RECT_TOP_RIGHT);
		this.addMarker(strokedShape, this.getBounds().getMaxX(), this
				.getBounds().getCenterY(), MarkerType.RECT_RIGHT_CENTRE);
		this.addMarker(strokedShape, this.getBounds().getX(), this.getBounds()
				.getCenterY(), MarkerType.RECT_LEFT_CENTRE);
		this.addMarker(strokedShape, this.getBounds().getX(), this.getBounds()
				.getMaxY(), MarkerType.RECT_BOTTOM_LEFT);
		this.addMarker(strokedShape, this.getBounds().getCenterX(), this
				.getBounds().getMaxY(), MarkerType.RECT_BOTTOM_CENTER);
		this.addMarker(strokedShape, this.getBounds().getMaxX(), this
				.getBounds().getMaxY(), MarkerType.RECT_BOTTOM_RIGHT);

		this.addMarker(strokedShape, this.getBounds().getCenterX(), this
				.getBounds().getCenterY(), MarkerType.MOVE);

		return strokedShape;
	}

	@Override
	public void drag(double deltaX, double deltaY, MarkerType mType)
	{
		SVGRectElement rectElement = (SVGRectElement) this;

		double x = rectElement.getX().getValue();
		double y = rectElement.getY().getValue();
		double width = rectElement.getWidth().getValue();
		double height = rectElement.getHeight().getValue();

		double newX = x - deltaX;
		double newY = y - deltaY;

		switch (mType)
		{
			case MOVE:

				rectElement.getX().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (newX)));

				rectElement.getY().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (newY)));

				break;

			case RECT_TOP_LEFT:

				rectElement.getX().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (newX)));

				rectElement.getY().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (newY)));

				rectElement.getWidth().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (width + deltaX)));

				rectElement.getHeight().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (height + deltaY)));

				break;

			case RECT_TOP_CENTER:

				rectElement.getY().setValue(newY);

				rectElement.getY().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (newY)));

				rectElement.getHeight().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (height + deltaY)));

				break;

			case RECT_TOP_RIGHT:

				rectElement.getY().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (newY)));

				rectElement.getHeight().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (height + deltaY)));

				rectElement.getWidth().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (width - deltaX)));

				break;

			case RECT_LEFT_CENTRE:

				rectElement.getX().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (newX)));

				rectElement.getWidth().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (width + deltaX)));

				break;

			case RECT_RIGHT_CENTRE:

				rectElement.getWidth().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (width - deltaX)));

				break;

			case RECT_BOTTOM_LEFT:

				rectElement.getX().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (newX)));

				rectElement.getWidth().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (width + deltaX)));

				rectElement.getHeight().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (height - deltaY)));

				break;

			case RECT_BOTTOM_CENTER:

				rectElement.getHeight().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (height - deltaY)));

				break;

			case RECT_BOTTOM_RIGHT:

				rectElement.getWidth().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (width - deltaX)));

				rectElement.getHeight().setValueFromLength(
						new SVGLength(SVGLength.SVG_LENGTHTYPE_PX,
								(float) (height - deltaY)));

				break;
		}

	}
}
